CH376的基础入门:基于ch376与SPI总线 的stm32f103c8t6与典型常用存储设备(TF卡,U盘)的通信 | 您所在的位置:网站首页 › u盘电路图原理解析 视频 › CH376的基础入门:基于ch376与SPI总线 的stm32f103c8t6与典型常用存储设备(TF卡,U盘)的通信 |
此文章所用学习板出于通用性考虑, 使用了ch376 进行TF卡与f103c8t6的SPI总线进行通信 利用ch376强大的CMD功能 对连接的存储设备进行写入,擦除等一系列操作(此类操作以连接在ch376上的u盘为例) 此文章仅涉及ch376的基础使用方法 更多内容可以关注作者 作者会在其他文章中继续整活 硬件使用基础
NSS CH376基础上 SPI与TF卡的通信 同时由ch376 的 16-13脚引出到 S DO,S DL,SCLK,S CSS 再次引入到单片机的SPI进行通信 需要添加 Lib stm32f10x_spi.cBasic sys.c spi.cHardwawre ch376.c filesys.c SPI总线的初始化spi.c #include "spi.h" void SPI2_Init(void){ //SPI2初始化 SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);//使能SPI_2时钟 GPIO_InitStructure.GPIO_Pin = SPI2_MISO; //SPI2的MISO(PB14)为浮空输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(SPI2PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SPI2_MOSI | SPI2_SCK; //SPI2的MOSI(PB15)和SCLK(PB13)为复用推免输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(SPI2PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SPI2_NSS; //SPI2的NSS(PB12)为推免输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(SPI2PORT,&GPIO_InitStructure); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//双线输入输出全双工模式,SPI双线并行允许全双工模式运行 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置为SPI的主机模式(SCK主动产生时钟)(SCK由MASTER产生) SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//SPI数据大小:发送8位帧数据结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//空闲状态时SCK的状态,High为高电平,Low为低电平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//时钟相位,1表示在SCK的奇数沿边采样,2表示偶数沿边采样 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS由软件控件片选 //如果选择SPI_NSS_Hard,则需要在每次通信之前手动设置,且在之后再次手动关闭 /* //在stm32f103x_spi.h中 //#define SPI_NSS_Hard ((uint16_t)0x0000) //so we program like yhis #if !SPI_InitStructure.SPI_NSS #pragram u8 SPI2_SendByte(u8 Byte) { GPIO_Pin_12/SPI2_NSS = 0; while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI2,Byte); while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI2); SPI2_NSS = 1; } #endif */ SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//时钟的预分频值(0~256)单个时钟周期的长度,数字越大,通信越慢,信号越稳定 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //MSB高位在前 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC较验和的多项式 SPI_Init(SPI2,&SPI_InitStructure); //初始化SPI2的配置项 SPI_Cmd(SPI2,ENABLE); //使能SPI2 } //SPI2数据发+收程序(主要用于发送) u8 SPI2_SendByte(u8 Byte){ //通过SPI2口发送1个数据,同时接收1个数据 while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET); //如果发送寄存器数据没有发送完,循环等待 SPI_I2S_SendData(SPI2,Byte); //往发送寄存器写入要发送的数据 while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET); //如果接受寄存器没有收到数据,循环 return SPI_I2S_ReceiveData(SPI2); }有关 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //MSB高位在前 spi.h #ifndef __SPI_H #define __SPI_H #include "sys.h" #define SPI2PORT GPIOB //定义IO接口 #define SPI2_MOSI GPIO_Pin_15 //定义IO接口 #define SPI2_MISO GPIO_Pin_14 //定义IO接口 #define SPI2_SCK GPIO_Pin_13 //定义IO接口 #define SPI2_NSS GPIO_Pin_12 //定义IO接口 void SPI2_Init(void); u8 SPI2_SendByte(u8 Byte); #endif ch376的使用command命令的使用与说明 ch376数据手册下载地址 阅读P3的 5、命令 对应 ch376inc.h 头文件 与 ch376.h #ifndef __CH376_H #define __CH376_H #include "sys.h" #include "spi.h" #include "delay.h" #include "ch376inc.h" #define CH376_INTPORT GPIOA //定义IO接口 #define CH376_INT GPIO_Pin_15 //定义IO接口 void CH376_PORT_INIT( void ); /* CH376通讯接口初始化 */ void xEndCH376Cmd( void ); /* 结束SPI命令 */ void xWriteCH376Cmd( u8 mCmd ); /* 向CH376写命令 */ void xWriteCH376Data( u8 mData );/* 向CH376写数据 */ u8 xReadCH376Data( void ); /* 从CH376读数据 */ u8 Query376Interrupt( void );/* 查询CH376中断(INT#引脚为低电平) */ u8 mInitCH376Host( void ); /* 初始化CH376 */ #endif以上两个库文件可以保证简单的使用与日后扩展 以下是与spi总线配套的驱动程序 ch376.c #include "CH376.h"CH376接口的初始化 与 数据传输函数 /******************************************************************************* * 函 数 名 : CH376_PORT_INIT * 描 述 : 由于使用软件模拟SPI读写时序,所以进行初始化. * 如果是硬件SPI接口,那么可使用mode3(CPOL=1&CPHA=1)或 * mode0(CPOL=0&CPHA=0),CH376在时钟上升沿采样输入,下降沿输出,数 * 据位是高位在前. *******************************************************************************/ void CH376_PORT_INIT(void){ //CH376的SPI接口初始化 GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO的初始化枚举结构 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //选择端口号 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻 GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_SetBits(CH376_INTPORT,CH376_INT); //中断输入脚拉高电平 GPIO_SetBits(SPI2PORT,SPI2_NSS); //片选接口接高电平 } /******************************************************************************* SPI输出8个位数据. * 发送: u8 d:要发送的数据. *******************************************************************************/ void Spi376OutByte(u8 d){ //SPI发送一个字节数据 SPI2_SendByte(d); } /******************************************************************************* * 描 述 : SPI接收8个位数据. u8 d:接收到的数据. *******************************************************************************/ u8 Spi376InByte(void){ //SPI接收一个字节数据 while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET); //如果接受寄存器没有收到数据,循环 return SPI_I2S_ReceiveData(SPI2); } /******************************************************************************* * 描 述 : 向CH376写 数据. * 输 入 : u8 mData: * 要发送的数据. *******************************************************************************/ void xWriteCH376Data(u8 mData){ Spi376OutByte( mData ); delay_us(800); /* 确保读写周期大于0.6mS */ } /******************************************************************************* * 函 数 名 : xReadCH376Data * 描 述 : 从CH376读数据. *******************************************************************************/ u8 xReadCH376Data(void){ u8 i; delay_us(10); i = SPI2_SendByte(0xFF); return(i); }CH376的命令函数 与 中断使用函数 /******************************************************************************* * 描 述 : 向CH376写 命令. * 输 入 : u8 mCmd:要发送的命令. *******************************************************************************/ void xWriteCH376Cmd(u8 mCmd){ GPIO_SetBits(SPI2PORT,SPI2_NSS); /* 防止之前未通过xEndCH376Cmd禁止SPI片选 */ delay_us(20); /* 对于双向I/O引脚模拟SPI接口,那么必须确保已经设置SPI_SCS,SPI_SCK,SPI_SDI为输出 * 方向,SPI_SDO为输入方向 */ GPIO_ResetBits(SPI2PORT,SPI2_NSS); /* SPI片选有效 */ Spi376OutByte( mCmd ); /* 发出命令码 */ delay_us(1700); /* 延时1.5mS确保读写周期大于1.5mS,或者用上面一行的状态查询代替 */ } /******************************************************************************* * 函 数 名 : xEndCH376Cmd 结束命令. *******************************************************************************/ void xEndCH376Cmd(void){ //结束命令 GPIO_SetBits(SPI2PORT,SPI2_NSS); //SPI片选无效,结束CH376命令 } /******************************************************************************* * 描 述 : 查询CH376中断(INT#低电平). * 返 回 : 0:无中断. 1:有中断. *******************************************************************************/ u8 Query376Interrupt(void){ u8 i; i = GPIO_ReadInputDataBit(CH376_INTPORT,CH376_INT); return( i ); }Ch376的初始化 与 通信检查 Ps: 前面都是前摇,main.c中只使用这一条 /******************************************************************************* * 描 述 : 初始化CH376. * 返 回 : FALSE:无中断. TRUE:有中断. *******************************************************************************/ u8 mInitCH376Host(void){ u8 res; delay_ms(600); CH376_PORT_INIT( ); /* 接口硬件初始化 */ xWriteCH376Cmd( CMD11_CHECK_EXIST ); /* 测试单片机与CH376之间的通讯接口 */ xWriteCH376Data( 0x55 ); res = xReadCH376Data( ); // printf("res =%02x \n",(unsigned short)res); xEndCH376Cmd( ); if ( res != 0xAA ) return( ERR_USB_UNKNOWN ); /* 通讯接口不正常,可能原因有:接口连接异常,其它设备影响(片选不唯一),串口波特率,一直在复位,晶振不工作 */ xWriteCH376Cmd( CMD11_SET_USB_MODE ); /* 设备USB工作模式 */ xWriteCH376Data( 0x06 ); //06H=已启用的主机方式并且自动产生SOF包 ??? delay_us(20); res = xReadCH376Data( ); // printf("res =%02x \n",(unsigned short)res); xEndCH376Cmd( ); if ( res == CMD_RET_SUCCESS ){ //RES=51 命令操作成功 return( USB_INT_SUCCESS ); //USB事务或者传输操作成功 }else{ return( ERR_USB_UNKNOWN );/* 设置模式错误 */ } } 在以上程序的基础上对TF卡进行通信的程序示例仅用于TF卡是否连接的检测 数据的读写请继续向下阅读 main.c #include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "touch_key.h" #include "relay.h" #include "oled0561.h" #include "spi.h" #include "ch376.h" #include"filesys.h" int main (void){//主程序 u8 s; delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 TOUCH_KEY_Init();//触摸按键初始化 RELAY_Init();//继电器初始化 I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化 OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串 OLED_DISPLAY_8x16_BUFFER(2," U DISK TEST "); //显示字符串 //CH376初始化 SPI2_Init();//SPI接口初始化 if(mInitCH376Host()== USB_INT_SUCCESS){//CH376初始化 OLED_DISPLAY_8x16_BUFFER(4," CH376 OK! "); //显示字符串 } while(1){ s = CH376DiskConnect(); //读出U盘的状态 if(s == USB_INT_SUCCESS){ //检查U盘是否连接//等待U盘插入 OLED_DISPLAY_8x16_BUFFER(6," U DISK Ready! "); //显示字符串 }else{ OLED_DISPLAY_8x16_BUFFER(6," "); //显示字符串 } delay_ms(500); //刷新的间隔 } } |
CopyRight 2018-2019 实验室设备网 版权所有 |